package com.heima.admin.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.heima.admin.mapper.AdChannelMapper;
import com.heima.admin.mapper.AdSensitiveMapper;
import com.heima.admin.service.WemediaNewsAutoScanService;
import com.heima.aliyun.GreenImageScan;
import com.heima.aliyun.GreenTextScan;
import com.heima.common.exception.CustException;
import com.heima.feigns.ArticleFeign;
import com.heima.feigns.WemediaFeign;
import com.heima.model.admin.pojo.AdChannel;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.utils.common.SensitiveWordUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WemediaNewsAutoScanServiceImpl implements WemediaNewsAutoScanService {

    @Autowired
    WemediaFeign wemediaFeign;

    @Value("${file.oss.web-site}")
    String webSite;

    /**
     * 自媒体文章审核
     * @param wmNewsId
     */
    @Override
    public void autoScanByMediaNewsId(Integer wmNewsId) {
        //1.根据自媒体文章id 远程查询自媒体文章信息
        ResponseResult<WmNews> wmNewsRes = wemediaFeign.findById(wmNewsId);
        if (wmNewsRes.getCode().intValue() != 0) {
            log.error("远程调用自媒体文章信息失败 文章id：{}  原因：{}", wmNewsId, wmNewsRes.getErrorMessage());
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID,"远程获取自媒体文章信息失败");
        }
        WmNews wmNews = wmNewsRes.getData();
        if (wmNews == null) {
            log.error("未获取自媒体文章信息失败 文章id：{}  原因：{}", wmNewsId, wmNewsRes.getErrorMessage());
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "未获取到自媒体文章信息");
        }
        //2.判断状态是否为4或8 ， 检查发布时间是否小于或等于当前时间
        Short status = wmNews.getStatus();
        if ((status == WmNews.Status.ADMIN_SUCCESS.getCode() || status == WmNews.Status.SUCCESS.getCode())
                && wmNews.getPublishTime().getTime() <= System.currentTimeMillis()) {
            //满足条件 发布视频
            publishArticle(wmNews);
            return;
        }
        //3.判断状态是否为1（待审核），进行审核操作
        if (status == WmNews.Status.SUBMIT.getCode()) {
            //3.1  抽取文章中所有的文本内容 和 图片url路径
            Map<String,Object> contentAndImages = handleTextAndImages(wmNews);
            //3.2  使用DFA算法审核内容（2审核失败）
            boolean sensitiveScan = handleSensitive((String) contentAndImages.get("content"), wmNews);
            if (!sensitiveScan) return;
            //3.3  使用阿里云安全审核内容（2失败 3人工审核）
            boolean textScan = handleTextScan((String) contentAndImages.get("content"), wmNews);
            if (!textScan) return;
            //3.4  使用阿里云安全审核图片（2失败 3人工审核）
            List<String> images = (List<String>) contentAndImages.get("images");
            if (images != null && images.size() > 0) {
                boolean imagesScan = handleImagesScan(images, wmNews);
                if (!imagesScan) return;
            }
            //4.判断当前时间是否小于发布时间
            if (new Date().before(wmNews.getPublishTime())) {
                //满足条件修改状态为8
                updateWmNews(wmNews, (short) 8, "审核通过");
                return;
            }
            //5.满足条件 发布文章
            publishArticle(wmNews);
        }

    }

    @Autowired
    GreenImageScan greenImageScan;

    //阿里云图片审核
    private boolean handleImagesScan(List<String> images, WmNews wmNews) {
        boolean flag = true;
        try {
            Map map = greenImageScan.imageUrlScan(images);
            String suggestion = (String) map.get("suggestion");
            if ("review".equals(suggestion)) {
                flag = false;
                updateWmNews(wmNews, (short) 3, "图片中有不确定的内容，转为人工审核");
            }
            if ("bolok".equals(suggestion)) {
                flag = false;
                updateWmNews(wmNews, (short) 2, "图片违规，审核失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
            updateWmNews(wmNews,(short) 3,"阿里云图片审核调用失败，转为人工审核");
        }
        return flag;
    }

    @Autowired
    GreenTextScan greenTextScan;

    //阿里云文本审核
    private boolean handleTextScan(String content, WmNews wmNews) {
        boolean flag = true;
        try {
            Map map = greenTextScan.greenTextScan(content);
            String suggestion = (String) map.get("suggestion");
            if ("review".equals(suggestion)) {
                flag = false;
                updateWmNews(wmNews, (short) 3, "文本中有不确定的内容，转为人工审核");
            }
            if ("bolok".equals(suggestion)) {
                flag = false;
                updateWmNews(wmNews, (short) 2, "文本中有违规词汇，审核失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
            updateWmNews(wmNews,(short) 3,"阿里云文本审核失败,转为人工审核");
        }
        return flag;
    }

    @Autowired
    AdSensitiveMapper adSensitiveMapper;

    private boolean handleSensitive(String content, WmNews wmNews) {
        boolean flag = true;
        //1.查询铭感词列表
        List<String> allSensitives = adSensitiveMapper.findAllSensitives();
        //2.封装为DFA数据模型
        SensitiveWordUtil.initMap(allSensitives);
        //3.基于DFA进行敏感词检测
        Map<String, Integer> resultMap = SensitiveWordUtil.matchWords(content);
        if (resultMap != null && resultMap.size() > 0) {
            //包含敏感词
            flag = false;
            //将文章状态修改为2
            updateWmNews(wmNews, (short) 2, "内容中包含敏感词：" + resultMap);
        }
        return flag;
    }

    private void updateWmNews(WmNews wmNews, short status, String reason) {
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        ResponseResult responseResult = wemediaFeign.updateWmNews(wmNews);
        if (responseResult.getCode().intValue() != 0) {
            log.error("远程调用wemedia修改wmNews失败  : {}", responseResult.getErrorMessage());
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR,"远程调用wemedia修改wmNews失败");
        }
    }

    /**
     * 抽取文章中所有文本内容和图片url
     * @param wmNews
     * @return
     */
    private Map<String, Object> handleTextAndImages(WmNews wmNews) {
        if (StringUtils.isBlank(wmNews.getContent()) || wmNews.getContent().length() > 10000) {
            log.error("文章的内容参数错误 ==> {}", wmNews.getContent());
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID);
        }
        //1.将文章内容转换为 List<Map> contentMap
        List<Map> contentMap = JSONArray.parseArray(wmNews.getContent(), Map.class);
        //2.抽取 文本 （标题 _ 内容）
        StringBuilder stringBuilder = new StringBuilder(wmNews.getTitle() + "-hmtt-");
        //2.1 使用filter过滤type=text数据  2.2 获取对应value值
        String content = contentMap.stream()
                .filter(map -> "text".equals(map.get("type")))
                .map(map -> (String) map.get("value"))
                .collect(Collectors.joining("-hmtt-"));
        stringBuilder.append(content);
        //3.抽取 图片 （封面 _ 内容）
        List<String> images = contentMap.stream()
                .filter(map -> "image".equals(map.get("type")))
                .map(map -> (String) map.get("value"))
                .collect(Collectors.toList());
        if (StringUtils.isNotBlank(wmNews.getImages())) {
            //如果封面不为空 获取封面图片url
            List<String> coverUrls = Arrays.stream(wmNews.getImages().split(","))
                    .map(url -> webSite + url)
                    .collect(Collectors.toList());
            //合并到上面的路径集合
            images.addAll(coverUrls);
        }
        //去除封面和内容重复的图片
        images = images.stream().distinct().collect(Collectors.toList());
        Map result = new HashMap();
        result.put("content", stringBuilder.toString());
        result.put("images", images);
        return result;
    }

    @Autowired
    ArticleFeign articleFeign;

    //发布文章的方法
    private void publishArticle(WmNews wmNews) {
        //  1. 远程调用saveArticle 保存三张表的信息
        ResponseResult responseResult = saveArticle(wmNews);
        if (responseResult.getCode().intValue() != 0) {
            log.error("远程保存apArticle信息失败 ==>{}", responseResult.getErrorMessage());
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR,"远程保存apArticle信息失败");
        }
        //  2. 修改自媒体文章状态
        wmNews.setArticleId((Long)responseResult.getData());
        updateWmNews(wmNews,(short) 9,"发布成功");
        // TODO 3. 通知ES索引库 添加对应文章


    }

    @Autowired
    AdChannelMapper adChannelMapper;

    //远程调用feign保存关联三表信息
    private ResponseResult saveArticle(WmNews wmNews) {
        ArticleDto articleDto = new ArticleDto();
        BeanUtils.copyProperties(wmNews, articleDto);
        //如果之前没发布过 id为null  发布过为之前关联的articleId
        articleDto.setId(wmNews.getArticleId());
        articleDto.setLayout(wmNews.getType());
        if (wmNews.getChannelId() != null) {
            AdChannel channel = adChannelMapper.selectById(wmNews.getId());
            articleDto.setChannelName(channel.getName());
        }
        articleDto.setFlag((byte) 0);
        articleDto.setWmUserId(wmNews.getUserId());
        return articleFeign.saveArticle(articleDto);
    }
}
